﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Physis.Core {

    public class CoreObject {

        #region Private Properties 

        private Application application = null;


        private Int64 id = 0;

        private String name = String.Empty;

        private String description = String.Empty;


        private String createId = String.Empty;

        private DateTime createDateTime = DateTime.Now;

        private String modifiedId = String.Empty;

        private DateTime modifiedDateTime = DateTime.Now;

        #endregion 


        #region Public Properties 

        [System.Web.Script.Serialization.ScriptIgnore]
        [Newtonsoft.Json.JsonIgnore]
        public virtual Application Application { get { return application; } set { application = value; } }


        public Int64 Id { get { return id; } protected set { id = value; } }

        public virtual String Name { get { return name; } set { name = Data.Functions.SetValueMaxLength (value, 60); } }

        public virtual String Description { get { return description; } set { description = Data.Functions.SetValueMaxLength (value, 999); } }


        public String CreateId { get { return createId; } set { createId = Data.Functions.SetValueMaxLength (value, 60); } }

        public DateTime CreateDateTime { get { return createDateTime; } set { createDateTime = value; } }

        public String ModifiedId { get { return modifiedId; } set { modifiedId = Data.Functions.SetValueMaxLength (value, 60); } }

        public DateTime ModifiedDateTime { get { return modifiedDateTime; } set { modifiedDateTime = value; } }


        public String ObjectType { get { return GetType ().Name; } }

        #endregion 


        #region Constructors 

        protected CoreObject () { return; }

        public CoreObject (Application forApplication) : this () {

            application = forApplication;

            return;

        }

        public CoreObject (Application forApplication, Int64 forId) : this (forApplication) {

            if (!Load (forId)) {

                throw new Exception (GetType ().FullName + ".Load [Failed]: " + forId);

            }

            return;

        }

        public CoreObject (Application forApplication, String forName) : this (forApplication) {

            return;

        }

        #endregion 


        #region Database Functions 

        protected Boolean LoadFromDatabase (String selectStatement, Data.IDatabase database) {

            Boolean success = false;


            System.Data.DataTable dataTable = database.SelectDataTable (selectStatement);

            success = (dataTable.Rows.Count == 1);


            if (success) {

                MapDataFields (dataTable.Rows[0]);

                success = LoadChildObjects ();

            }


            return success;

        }

        protected Boolean Load (Application applicationReference, Int64 forId) {

            application = applicationReference;

            return Load (forId);

        }

        protected virtual Boolean Load (Int64 forId, Data.IDatabase database) {

            if (forId == 0) { return false; }

            return LoadFromDatabase (SelectStatementById (forId), database);

        }

        protected virtual Boolean Load (String forName, Data.IDatabase database) { 

            if (String.IsNullOrWhiteSpace (forName)) { return false; }

            return LoadFromDatabase ("SELECT * FROM " + ObjectType + " WHERE Name = '" + forName.Replace ("'", "''") + "'", database);

        }

        protected virtual Boolean Load (Int64 forId) {

            return Load (forId, application.EnvironmentDatabase);

        }

        protected virtual Boolean Load (String forName) {

            return Load (forName, application.EnvironmentDatabase);

        }

        protected virtual Boolean LoadChildObjects () { return true; }

        public virtual void MapDataFields (System.Data.DataRow currentRow) {

            id = Data.Readers.DataReader.Int64FromDatabase (currentRow, "Id");

            name = Data.Readers.DataReader.StringFromDatabase (currentRow, "Name");

            description = Data.Readers.DataReader.StringFromDatabase (currentRow, "Description", "Name");


            createId = Data.Readers.DataReader.StringFromDatabase (currentRow, "CreateId");

            createDateTime = Data.Readers.DataReader.DateTimeFromDatabase (currentRow, "CreateDateTime");

            modifiedId = Data.Readers.DataReader.StringFromDatabase (currentRow, "ModifiedId");

            modifiedDateTime = Data.Readers.DataReader.DateTimeFromDatabase (currentRow, "ModifiedDateTime");

            return;

        }


        protected virtual void SaveAppendCommandParameter (System.Data.IDbCommand command, Boolean appendId, Boolean appendName, Boolean appendDescription, Boolean appendModifiedId) {

            if (appendId) { Application.EnvironmentDatabase.AppendCommandParameter (command, "Id", Id); }

            if (appendName) { Application.EnvironmentDatabase.AppendCommandParameter (command, "Name", Name, Data.DataTypeConstants.Name); }

            if (appendDescription) { Application.EnvironmentDatabase.AppendCommandParameter (command, "Description", Description, Data.DataTypeConstants.Description); }

            if (appendModifiedId) { Application.EnvironmentDatabase.AppendCommandParameter (command, "ModifiedId", Application.Session.UserAccountName, Data.DataTypeConstants.Description); }

            return;

        }

        public virtual Boolean Save () { return false; }

        public Boolean Save (Application forApplication) {

            application = forApplication;

            return Save ();

        }


        protected virtual String SelectStatementById (Int64 forId = 0) {

            return "SELECT * FROM " + ObjectType + " WHERE Id = " + ((forId != 0) ? forId : Id); 

        }

        protected virtual String DeleteStatementById () {

            return "DELETE FROM " + ObjectType + " WHERE Id = " + Id;

        }


        protected Boolean DeleteFromDatabase (String deleteStatement, Data.IDatabase database) {

            Boolean success = false;

            success = database.ExecuteSqlStatement (deleteStatement);

            if (!success) {

                Application.SetLastException (database.LastException);

            }

            return success;

        }

        public virtual Boolean Delete () {

            return DeleteFromDatabase (DeleteStatementById (), application.EnvironmentDatabase);

        }

        #endregion 


        #region Identity Methods

        public void SetIdentity (Data.IDatabase database, String sequenceName) {

            if (id != 0) { return; }

            id = database.IdentityGet (sequenceName);

            return;

        }

        public void SetIdentity (Data.IDatabase database) {

            SetIdentity (database, String.Empty);

            return;

        }

        public void SetIdentity (String sequenceName) {

            SetIdentity (Application.EnvironmentDatabase, sequenceName);

            return;

        }

        public void SetIdentity () {

            SetIdentity (Application.EnvironmentDatabase, String.Empty);

            return;

        }
        
        #endregion 


        #region Public Methods

        protected virtual Dictionary<String, String> Validate () {

            Dictionary<String, String> validationErrors = new Dictionary<String, String> ();

            if (String.IsNullOrWhiteSpace (Name)) { validationErrors.Add ("Name", "Empty or invalid value for Name."); }

            if (String.IsNullOrWhiteSpace (Description)) { validationErrors.Add ("Description", "Empty or invalid value for Description."); }

            return validationErrors;

        }
        
        protected void UpdateModifiedToSessionUser () {

            ModifiedId = Application.Session.UserAccountName;

            ModifiedDateTime = DateTime.Now;

            return;

        }

        #endregion 

    }

}
